import os
import json
from PIL import Image
import io
import logging

def ensure_dir(path):
    if not os.path.exists(path):
        os.makedirs(path)


def save_image(image, out_path, quality=95):
    try:
        img_bytes = io.BytesIO(image.blob)
        img = Image.open(img_bytes)
        img.save(out_path, format='PNG', quality=quality)
        with open(os.path.join('output', 'run.log'), 'a', encoding='utf-8') as f:
            f.write(f"[调试] save_image: 保存图片到 {out_path}, image对象类型: {type(image)}, PIL类型: {type(img)}\n")
    except Exception as e:
        with open(os.path.join('output', 'run.log'), 'a', encoding='utf-8') as f:
            f.write(f"[调试] save_image: 保存图片失败 {out_path}, image对象类型: {type(image)}, 错误: {e}\n")
        raise


def export_images(images, out_dir, slide_num, naming_func, quality=95):
    ensure_dir(out_dir)
    exported = []
    with open(os.path.join('output', 'run.log'), 'a', encoding='utf-8') as f:
        f.write(f"[调试] export_images: images数量: {len(images)}\n")
    for idx, img_info in enumerate(images, 1):
        name = naming_func(slide_num, '图片', img_info['top'], img_info['name'], idx)
        out_path = os.path.join(out_dir, f"{name}.png")
        with open(os.path.join('output', 'run.log'), 'a', encoding='utf-8') as f:
            f.write(f"[调试] export_images: 正在保存图片 {name}, out_path={out_path}, img_info_keys={list(img_info.keys())}, has_image={'image' in img_info}, image_type={type(img_info.get('image', None)) if 'image' in img_info else None}\n")
        save_image(img_info['image'], out_path, quality)
        rel_path = os.path.relpath(out_path, os.path.dirname(out_dir))
        img_info['image_path'] = rel_path.replace('\\', '/')
        exported.append({'name': name, 'path': out_path, 'meta': img_info})
    return exported


def export_texts(texts, out_dir, slide_num, naming_func):
    ensure_dir(out_dir)
    exported = []
    for idx, txt_info in enumerate(texts, 1):
        name = naming_func(slide_num, '文本', txt_info['top'], txt_info['name'], idx)
        out_path = os.path.join(out_dir, f"{name}.json")
        with open(out_path, 'w', encoding='utf-8') as f:
            json.dump(txt_info, f, ensure_ascii=False, indent=2)
        exported.append({'name': name, 'path': out_path, 'meta': txt_info})
    return exported


def export_tables(tables, out_dir, slide_num, naming_func):
    ensure_dir(out_dir)
    exported = []
    for idx, tbl_info in enumerate(tables, 1):
        name = naming_func(slide_num, '表格', tbl_info['top'], tbl_info['name'], idx)
        out_path = os.path.join(out_dir, f"{name}.json")
        with open(out_path, 'w', encoding='utf-8') as f:
            json.dump(tbl_info, f, ensure_ascii=False, indent=2)
        exported.append({'name': name, 'path': out_path, 'meta': tbl_info})
    return exported


def strip_unserializable(obj):
    if isinstance(obj, dict):
        # 移除'image'字段，递归处理其它字段
        return {k: strip_unserializable(v) for k, v in obj.items() if k != 'image'}
    elif isinstance(obj, list):
        return [strip_unserializable(i) for i in obj]
    elif isinstance(obj, Image.Image):
        return None  # 或者返回图片路径等
    else:
        return obj


def export_layout(layout, out_dir, slide_num, slide_width=None, slide_height=None):
    ensure_dir(out_dir)
    out_path = os.path.join(out_dir, f"{slide_num}_布局.json")
    # 只strip layout，不影响parsed['images']
    layout_clean = strip_unserializable(layout)
    # 自动兼容dict或list
    if isinstance(layout_clean, dict) and 'elements' in layout_clean:
        elements = layout_clean['elements']
    else:
        elements = layout_clean
    layout_obj = {
        'slide_width': int(slide_width) if slide_width else None,
        'slide_height': int(slide_height) if slide_height else None,
        'elements': elements
    }
    with open(out_path, 'w', encoding='utf-8') as f:
        json.dump(layout_obj, f, ensure_ascii=False, indent=2)
    return out_path


def chinese_naming(slide_num, elem_type, top, group_name, idx):
    # 位置描述简化为"顶部""中部""底部"
    pos = '顶部' if top < 2000000 else ('底部' if top > 4000000 else '中部')
    group = group_name if group_name else '无组合'
    return f"{slide_num}_{elem_type}_{pos}_{group}_{idx}" 